﻿Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports FuncClasses
Imports System.Threading.Tasks
Imports System.Threading
Imports System.Windows.Threading

Public Class CustomerViewModel
    Implements INotifyPropertyChanged

    Private _allcustomers As ObservableCollection(Of CustomerPreviewModel)
    Private _displayedcustomers As ObservableCollection(Of CustomerPreviewModel)
    Private db As IDatabase
    Private _dispatcher As Windows.Threading.Dispatcher
    Private _searchpattern, _category As String
    Private _usr As User

    Public Sub New(loader As IDatabase, dispatcher As Windows.Threading.Dispatcher, usr As User)
        db = loader
        _dispatcher = dispatcher
        _searchpattern = ""
        _category = ""
        _usr = usr
        Task.Factory.StartNew(AddressOf LoadCustomers)
    End Sub

    Public Property SearchPattern As String
        Get
            Return _searchpattern
        End Get
        Set(value As String)
            _searchpattern = value
            NotifyPropertyChanged("SearchPattern")
            Task.Factory.StartNew(AddressOf ApplySearchPattern)
        End Set
    End Property

    Public Property XPathCategory As String
        Get
            Return _category
        End Get
        Set(value As String)
            _category = value
            NotifyPropertyChanged("XPathCategory")
            Task.Factory.StartNew(AddressOf ApplySearchPattern)
        End Set
    End Property

    Public Property AllCustomers As ObservableCollection(Of CustomerPreviewModel)
        Get
            Return _allcustomers
        End Get
        Set(value As ObservableCollection(Of CustomerPreviewModel))
            _allcustomers = value
            NotifyPropertyChanged("AllCustomers")
        End Set
    End Property

    Public Property DisplayedCustomers As ObservableCollection(Of CustomerPreviewModel)
        Get
            Return _displayedcustomers
        End Get
        Set(value As ObservableCollection(Of CustomerPreviewModel))
            _displayedcustomers = value
            NotifyPropertyChanged("DisplayedCustomers")
        End Set
    End Property

    Private Sub LoadCustomers()
        Dim temp As ObservableCollection(Of CustomerPreviewModel) = db.GetAllCustomers(_usr)
        _dispatcher.BeginInvoke(Sub()
                                    AllCustomers = temp
                                    Task.Factory.StartNew(AddressOf ApplySearchPattern)
                                End Sub)
    End Sub

    Private Sub ApplySearchPattern()
        Dim temp As New Collection(Of CustomerPreviewModel)
        Dim m As New Mutex
        Parallel.ForEach(AllCustomers, Sub(customer As CustomerPreviewModel)
                                           If customer.Address.ToLower.Contains(SearchPattern.ToLower) OrElse customer.CustomerID.ToLower.Contains(SearchPattern.ToLower) Then
                                               m.WaitOne()
                                               temp.Add(customer)
                                               m.ReleaseMutex()
                                           End If
                                       End Sub)

        Dim temp2 As New ObservableCollection(Of CustomerPreviewModel)
        Parallel.ForEach(temp, Sub(customer As CustomerPreviewModel)
                                   If customer.DisplayedName.ToLower.StartsWith(XPathCategory.ToLower) OrElse String.IsNullOrEmpty(XPathCategory) Then
                                       m.WaitOne()
                                       temp2.Add(customer)
                                       m.ReleaseMutex()
                                   End If
                               End Sub)
        Dim output As New ObservableCollection(Of CustomerPreviewModel)
        Dim sortedCo = From item In temp2 Order By item.CustomerID Ascending
        For Each item In sortedCo
            output.Add(item)
        Next
        _dispatcher.BeginInvoke(Sub()
                                    DisplayedCustomers = output
                                End Sub)
    End Sub

    Public Sub Refresh()
        Task.Factory.StartNew(AddressOf LoadCustomers)
    End Sub

    Public Sub SaveCustomer(customer As Customer)
        db.SaveOrUpdateCustomer(customer, _usr)
        If _usr.CanWriteCustomer Then
            Dim prev As New CustomerPreviewModel With {.Address = customer.Address.ToString, .CustomerID = customer.CustomerID, .DisplayedName = customer.DisplayName}
            If AllCustomers.Contains(prev) Then
                AllCustomers(AllCustomers.IndexOf(prev)) = prev
            Else
                AllCustomers.Add(prev)
            End If
            Task.Factory.StartNew(AddressOf ApplySearchPattern)
        End If
    End Sub

    Protected Sub NotifyPropertyChanged(info As [String])
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub
    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

#Region "Sorting Displayed Items"
    Private _sortiddirection As ListSortDirection = ListSortDirection.Ascending
    Private _sortnamedirection As ListSortDirection = ListSortDirection.Descending
    Private _sortaddressdirection As ListSortDirection = ListSortDirection.Descending

    Public Sub SortByID()
        If _sortiddirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedCustomers Order By item.CustomerID Ascending)
            _sortiddirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedCustomers Order By item.CustomerID Descending)
            _sortiddirection = ListSortDirection.Descending
        End If
    End Sub

    Public Sub SortByName()
        If _sortnamedirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedCustomers Order By item.DisplayedName Ascending)
            _sortnamedirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedCustomers Order By item.DisplayedName Descending)
            _sortnamedirection = ListSortDirection.Descending
        End If
    End Sub

    Public Sub SortByAddress()
        If _sortaddressdirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedCustomers Order By item.Address Ascending)
            _sortaddressdirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedCustomers Order By item.Address Descending)
            _sortaddressdirection = ListSortDirection.Descending
        End If
    End Sub

    Private Sub LinqToCol(sortedCo As System.Linq.IOrderedEnumerable(Of CustomerPreviewModel))
        Dim output As New ObservableCollection(Of CustomerPreviewModel)
        For Each item In sortedCo
            output.Add(item)
        Next
        DisplayedCustomers = output
    End Sub
#End Region
End Class
